﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Text;

namespace Common.DataAnnotations
{
    /// <summary>
    /// 依赖必填
    /// </summary>
    public class DependencyRequiredAttribute : ValidationAttribute
    {
        private readonly string dependencyPropertyName;
        private readonly object[] dependencyValues;
        /// <summary>
        /// 依赖必填
        /// </summary>
        /// <param name="dependencyProperty">依赖的属性名</param>
        /// <param name="dependencyValues">依赖的属性可选值（当依赖的属性为这些值时，被标记的属性必填）,传入 null 时仅校验是否为空</param>
        public DependencyRequiredAttribute(string dependencyProperty, params object[] dependencyValues)
        {
            this.dependencyPropertyName = dependencyProperty;
            this.dependencyValues = dependencyValues;
        }
        /// <summary>
        /// 
        /// </summary>
        public string DependencyPropertyDisplayName { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public override bool RequiresValidationContext => true;
        private object MatchedDependencyValue;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public override string FormatErrorMessage(string name)
        {
            string message = this.MatchedDependencyValue == null ? "当{1}有值时{0}不允许为空" : "当{1}的值为{2}时{0}不允许为空";
            return string.Format(ErrorMessage ?? message, name, DependencyPropertyDisplayName, this.MatchedDependencyValue);
        }
        /// <inheritdoc/>
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var property = validationContext.ObjectType.GetProperty(this.dependencyPropertyName);
            if (property == null)
            {
                return new ValidationResult($"{validationContext.DisplayName}指定的依赖属性不存在");
            }
            this.DependencyPropertyDisplayName = property.GetCustomAttribute<DisplayAttribute>()?.Name ?? property.Name;
            var dependencyValue = property.GetValue(validationContext.ObjectInstance);
            if (dependencyValue == null)
            {
                return null;
            }
            if (!HasDependencyValue && value == null)
            {
                //无依赖值
                return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
            }
            else if (HasDependencyValue && dependencyValues.Contains(dependencyValue) && value == null)
            {
                this.MatchedDependencyValue = dependencyValue;
                //有依赖值，并且命中依赖值
                return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
            }
            return null;
        }
        private bool HasDependencyValue => dependencyValues != null && dependencyValues.Any();
    }
}
